import numpy as np
import matplotlib.pyplot as plt

def loadDataSet(fileName, delim='\t'):
    fr = open(fileName)
    dataMat = []
    for line in fr.readlines():
        lineArr = line.strip().split(delim)
        fltLine = list(map(float, lineArr))
        dataMat.append(fltLine)
    return np.mat(dataMat)


# def loadDataSet1(fileName):
#     fr = open(fileName)
#     stringArr = [line.strip().split('\t') for line in fr.readlines()]
#     datArr = [list(map(float, line)) for line in stringArr]
#     return np.mat(datArr)


def pca(dataMat, topNfeat=9999999):
    meanVals = np.mean(dataMat, axis=0) # 计算出矩阵每列特征的均值,
    meanRemoved = dataMat - meanVals # 去平均值
    covMat = np.cov(meanRemoved, rowvar=0) # 如果rowvar为True（默认值），则每行代表一个变量X，另一个行为变量Y。
    eigVals, eigVects = np.linalg.eig(np.mat(covMat)) #通过linalg.eig()算出特征值和特征向量
    eigValInd = np.argsort(eigVals)  # 对特征值进行排序,得出的是下标
    # print(eigValInd)
    eigValInd = eigValInd[:-(topNfeat+1):-1]
    #print(eigValInd)
    redEigVects = eigVects[:, eigValInd]
    lowDataMat = meanRemoved * redEigVects
    reconMat = (lowDataMat * redEigVects.T) + meanVals
    return lowDataMat, reconMat


def showPic(dataMat, reconMat):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    # 三角形表示原始数据点
    ax.scatter(dataMat[:, 0].flatten().A[0], dataMat[:, 1].flatten().A[0], marker='^', s=90)
    # 圆形点表示第一主成分点，点颜色为红色
    ax.scatter(reconMat[:, 0].flatten().A[0], reconMat[:, 1].flatten().A[0], marker='o', s=90, c='red')
    plt.show()


def replaceNanWithMean(): # 将NaN替换成平均值的函数
    dataMat = loadDataSet('secom.data',' ')
    numFeat = np.shape(dataMat)[1] # 获取特征数目
    for i in range(numFeat):
        meanVal = np.mean(dataMat[np.nonzero(~np.isnan(dataMat[:, i].A))[0], i])
        dataMat[np.nonzero(np.isnan(dataMat[:, i].A))[0], i] = meanVal
    return dataMat



if __name__ == '__main__':
    # dataMat = loadDataSet('testSet.txt')
    # #print(dataMat)
    # lowDataMat, reconMat = pca(dataMat, 1)
    # print(np.shape(lowDataMat))
    # showPic(dataMat, reconMat)
    dataMat = replaceNanWithMean()
    meanVals = np.mean(dataMat, axis=0)
    meanRemoved = dataMat - meanVals
    covMat = np.cov(meanRemoved, rowvar=0)
    eigVals, eigVects = np.linalg.eig(np.mat(covMat))
    print(sum(eigVals) * 0.9)  # 计算90%的主成分方差总和
    print(sum(eigVals[:6]))  # 计算前6个主成分所占的方差
    plt.plot(eigVals[:20], marker='^')  # 对前20个画图观察
    plt.show()
